0%

SpringAI — Tool Search Tool(工具搜索工具)

随着 AI Agent 连接的服务增多(Slack、GitHub、Jira、MCP 服务器等),工具库迅速膨胀。一个典型的多服务器设置很容易拥有 50+ 工具,在对话开始之前就消耗 55,000+ Token。当模型面对 30+ 名称相似的工具时,工具选择准确性也会下降。

工具搜索工具模式通过按需工具发现解决这个问题:

Spring AI 在2.0版本提供了该机制,可用于实现Tool的渐进加载,更好的为agent服务

  1. 模型初始只收到一个搜索工具 — 最小化 Token 使用
  2. 当需要某种能力时,模型用自然语言查询调用搜索工具
  3. 匹配的工具定义被动态展开到上下文中
  4. 模型随后可以正常调用被发现的工具

这实现了显著的 Token 节省,同时保持对大型工具目录的访问。

运行时流程

ToolSearchToolCallingAdvisor 扩展了 Spring AI 的 ToolCallingAdvisor,实现了动态工具发现。

运行时流程如下:

  1. 索引 — 对话开始时,所有已注册的工具都会被索引到 ToolIndex 中,但不会发送到 LLM
  2. 初始请求 — 仅将内置的 toolSearchTool 定义发送到 LLM
  3. 发现调用 — 当 LLM 需要某个功能时,它会使用搜索查询调用 toolSearchTool
  4. 搜索与扩展 — ToolIndex 找到匹配的工具;它们的定义会被添加到下一个请求中
  5. 工具调用 — LLM 可以看到 toolSearchTool 和已发现的工具定义,并可以调用实际的工具
  6. 工具执行 — 已发现的工具被执行,其结果返回给 LLM
  7. 响应 — LLM 使用工具结果生成最终答案

三种索引策略

类型 实现类 匹配方式 适用场景
语义 Semantic VectorToolIndex 基于嵌入的相似度搜索 自然语言描述,需 VectorStore
关键字 Keyword LuceneToolIndex Apache Lucene 精确词项匹配 已知工具名称,快速有效
正则 Regex RegexToolIndex 正则表达式匹配 工具名称遵循已知命名约定(如 get_*

Spring Boot Starter 配置

最简单的方式(包含 Lucene 和自动配置):

1
2
3
4
5
<!-- Maven -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-tool-search-advisor</artifactId>
</dependency>
1
2
// Gradle
implementation 'org.springframework.ai:spring-ai-starter-tool-search-advisor'

或手动使用库:

1
2
3
4
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-tool-search-tool</artifactId>
</dependency>

配置属性参考

属性 说明 默认值
spring.ai.chat.client.tool-search-advisor.enabled 启用 Advisor,为 true 时替换默认 ToolCallingAdvisor false
spring.ai.chat.client.tool-search-advisor.tool-index-type 索引实现:regex/lucene/vector regex
spring.ai.chat.client.tool-search-advisor.max-results 每次搜索返回的最大工具引用数 null(LLM 自行决定)
spring.ai.chat.client.tool-search-advisor.system-message-suffix 追加到系统消息的自定义提示后缀 null(使用内置模板)
spring.ai.chat.client.tool-search-advisor.reference-tool-name-accumulation 是否累积所有搜索调用中发现的工具名称 true
spring.ai.chat.client.tool-search-advisor.session-id-key-name 携带会话 ID 的 Advisor 上下文键 chat_memory_conversation_id
spring.ai.chat.client.tool-search-advisor.advisor-order Advisor 在链中的顺序 HIGHEST_PRECEDENCE + 300
spring.ai.chat.client.tool-search-advisor.eviction.lru-max-sessions LRU 驱逐策略保留的最大活跃会话数 1000
spring.ai.chat.client.tool-search-advisor.eviction.ttl 空闲会话的生存时间 null
spring.ai.chat.client.tool-search-advisor.lucene.min-score-threshold Lucene 命中的最低分数阈值 0.25

一键启用:

1
2
spring.ai.chat.client.tool-search-advisor.enabled: true
spring.ai.chat.client.tool-search-advisor.tool-index-type: lucene

ToolSearchToolCallingAdvisor Builder 配置

配置项 说明 默认值
toolIndex(ToolIndex) 使用的搜索实现(必填
maxResults(Integer) 每次搜索返回的最大工具引用数 null
systemMessageSuffix(String) 追加到系统消息的自定义提示后缀 内置模板
referenceToolNameAccumulation(boolean) 是否累积跨搜索调用的工具名称 true
sessionIdKeyName(String) 查找会话 ID 的上下文键 chat_memory_conversation_id
evictionStrategy(...) 会话索引释放策略 LruEvictionStrategy(1000)
advisorOrder(int) Advisor 在链中的位置 HIGHEST_PRECEDENCE + 300

会话驱逐策略

每次调用按 sessionId 隔离,工具索引在并发对话间相互隔离。

策略 说明
LruEvictionStrategy(maxSessions)(默认) 超过最大活跃会话数时驱逐最近最少使用的会话
NeverEvictStrategy.INSTANCE 永不自动驱逐,直到显式调用 evictSession()
AlwaysEvictStrategy.INSTANCE 每次请求前清除会话索引,强制完全重新索引
TtlEvictionStrategy(duration) 驱逐上次访问时间超过 TTL 的会话
CompositeEvictionStrategy(strategies...) 委托给多个策略,任一策略请求即驱逐

驱逐是惰性评估的——不需要后台线程。

适用场景

推荐使用:

  • 系统中有 10 个以上工具
  • 工具定义消耗超过 10K Token
  • 构建连接多个服务器的 MCP 驱动系统
  • 大型工具集出现工具选择准确性问题

传统方式可能更好:

  • 小型工具库(少于 10 个工具)
  • 每个会话中所有工具都被频繁使用
  • 工具定义非常紧凑